
#include "stdafx.h"

#include "CeBrain.h"

CeBrain::CeBrain(void)
{
	memset( m_pNervusNet, 0, sizeof(m_pNervusNet) );
	m_nNervusValuesCount = 0;

	m_pTrainingCaseDB = new CTrainingCaseDB();
	m_pTrainingCaseDB->BuildAllCase();
}


CeBrain::~CeBrain(void)
{
	delete m_pTrainingCaseDB;
}

void CeBrain::ClearNervusNet( int nIdx )
{
	delete m_pNervusNet[nIdx];
	m_pNervusNet[nIdx] = NULL;
}

void CeBrain::BuildNervusNet( int nIdx, OutputAntennaRate* tryRate, int nRateCount )
{
	if( m_pNervusNet[nIdx]==NULL )
		m_pNervusNet[nIdx] = new CNervusNet();

	//line 0:
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
		{
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 0 );
			pNervus->GetFirstOutputAntenna()->SetRate( SIGNAL_RATE );
		}
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( false, SIGNAL_RATE ));

		for( int x=0; x<2; x++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
			pNervus->AddOutputAntenna( new CNervusAntenna( true, SIGNAL_RATE) );
		}
		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 0, pNervus );
	}

	//line 1:
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
		{
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 1 );
			pNervus->GetFirstOutputAntenna()->SetRate( SIGNAL_RATE );
		}
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( false, SIGNAL_RATE ));

		for( int x=0; x<2; x++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
			pNervus->AddOutputAntenna( new CNervusAntenna( true, SIGNAL_RATE ) );
		}
		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 1, pNervus );
	}

	//line 2:
	for( int i=0; i<INPUT_SIGNAL_COUNT*2*2; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
		{
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 2 );
			pNervus->GetFirstOutputAntenna()->SetRate( 0.3 );
		}
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( false, 0.3 ));

		for( int x=0; x<2; x++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
		}

		for( int j=0; j<OUTPUT_SIGNAL_COUNT-1; j++ )
		{
			pNervus->AddOutputAntenna( new CNervusAntenna( false, 0.3 ) );
		}
		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 2, pNervus );
	}

	//line 3:
	for( int i=0; i<OUTPUT_SIGNAL_COUNT; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 3 );
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( ));
		for( int j=0; j<INPUT_SIGNAL_COUNT*2*2-1; j++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
		}
		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 3, pNervus );
	}

	NervusLink nl[1000];
	int nLinkCount=0;
	//0 to 1
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		NervusLink tmpnl={ {0,i}, 0, {1,i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		NervusLink tmpnl={ {0,i}, 1, {1,INPUT_SIGNAL_COUNT+i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		if( i==0 )
		{
			NervusLink tmpnl={ {0,i}, 2, {1,INPUT_SIGNAL_COUNT*2-1} };
			nl[nLinkCount++] = tmpnl;
		}
		else
		{
			NervusLink tmpnl={ {0,i}, 2, {1,INPUT_SIGNAL_COUNT+i-1} };
			nl[nLinkCount++] = tmpnl;
		}
	}
	//1 to 2
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		NervusLink tmpnl={ {1,i}, 0, {2,i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		NervusLink tmpnl={ {1,i}, 1, {2,INPUT_SIGNAL_COUNT*2+i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		if( i==0 )
		{
			NervusLink tmpnl={ {1,i}, 2, {2,INPUT_SIGNAL_COUNT*2*2-1} };
			nl[nLinkCount++] = tmpnl;
		}
		else
		{
			NervusLink tmpnl={ {1,i}, 2, {2,INPUT_SIGNAL_COUNT*2+i-1} };
			nl[nLinkCount++] = tmpnl;
		}
	}
	//2 to 3
	for( int i=0; i<INPUT_SIGNAL_COUNT*2*2; i++ )
		for( int j=0; j<OUTPUT_SIGNAL_COUNT; j++ )
		{
			NervusLink tmpnl={ {2,i}, j, {3,j} };
			nl[nLinkCount++] = tmpnl;
		}

	for( int i=0; i<nLinkCount; i++ )
		m_pNervusNet[nIdx]->MakeConnection( nl[i].posSource, nl[i].nSourcePinIdx, nl[i].posTarget );

	for( int i=0; i<nRateCount; i++ )
		m_pNervusNet[nIdx]->SetOutputAntennaRate( tryRate[i].posSource,  tryRate[i].nSourcePinIdx,  tryRate[i].fRate );
}

bool CeBrain::RunTrainingCase( int nIdx )
{
//	for( int i=0; i<OUTPUT_SIGNAL_COUNT; i++ )
//		m_nOutputSignal[i] = 0;

	CTrainingCase* pCase = m_pTrainingCaseDB->GetCase( nIdx );

	pCase->ConnectInputOutput( m_pNervusNet[nIdx] );
	pCase->InitOutSignal();

	for( int i=0; i<MAX_RUN_STEP; i++ )
	{
		//TRACE("==========step %d====\n",i);
		pCase->TransmitSignal();

		m_pNervusNet[nIdx]->ProcessSignal();

		pCase->GetOutputSignal();
	}

	bool bResult = pCase->CompareNervusOutputSignal( ) == RES_GOOD;
	return bResult;
}

float CeBrain::RunAllTrainingCase( OutputAntennaRate* tryRate, int nRateCount )
{
	int nOkCount = 0;

	#pragma omp parallel for
	for( int i=0; i<MAX_CASE; i++ )
	{
		BuildNervusNet(i, tryRate, nRateCount);

		if( RunTrainingCase( i ) )
			nOkCount++;
		ClearNervusNet(i);
	}
	float fPassRate = ((float)nOkCount)/MAX_CASE*100;
	TRACE( "Case Pass %d, when try %lf, pass rate: %f%%\n", nOkCount, tryRate[0].fRate, fPassRate );

	return fPassRate;
}

void CeBrain::BuildNervusNet2( int nIdx, OutputAntennaRate* tryRate1, OutputAntennaRate* tryRate2, OutputAntennaRate* tryRate3, OutputAntennaRate* tryRate4, int nRateCount )
{
	if( m_pNervusNet[nIdx]==NULL )
		m_pNervusNet[nIdx] = new CNervusNet();

	//line 0:
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
		{
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 0 );
			pNervus->GetFirstOutputAntenna()->SetRate( SIGNAL_RATE );
		}
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( false, SIGNAL_RATE ));

		for( int x=0; x<2; x++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
			pNervus->AddOutputAntenna( new CNervusAntenna( true, SIGNAL_RATE) );
		}
		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 0, pNervus );
	}

	//line 1:
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
		{
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 1 );
			pNervus->GetFirstOutputAntenna()->SetRate( SIGNAL_RATE );
		}
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( false, SIGNAL_RATE ));

		for( int x=0; x<2; x++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
			pNervus->AddOutputAntenna( new CNervusAntenna( true, SIGNAL_RATE ) );
		}
		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 1, pNervus );
	}

	//line 2:
	for( int i=0; i<INPUT_SIGNAL_COUNT*2*2; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
		{
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 2 );
			pNervus->GetFirstOutputAntenna()->SetRate( 0.3 );
		}
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( false, 0.3 ));

		for( int x=0; x<2; x++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
		}

		for( int j=0; j<OUTPUT_SIGNAL_COUNT*4-1; j++ )
		{
			pNervus->AddOutputAntenna( new CNervusAntenna( false, 0.3 ) );
		}
		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 2, pNervus );
	}

	//line 3:
	for( int i=0; i<OUTPUT_SIGNAL_COUNT*4; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 3 );
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( ));
		for( int j=0; j<INPUT_SIGNAL_COUNT*2*2-1; j++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
		}
		for( int j=0; j<OUTPUT_SIGNAL_COUNT-1; j++ )
		{
			pNervus->AddOutputAntenna( new CNervusAntenna( false, 0.3 ) );
		}

		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 3, pNervus );
	}
	//line 4:
	for( int i=0; i<OUTPUT_SIGNAL_COUNT; i++ )
	{
		CNervus* pNervus;
		if( i==0 )
			pNervus = m_pNervusNet[nIdx]->GetFirstNervusOfLine( 4 );
		else
			pNervus = new CNervus(new CNervusAntenna( ), new CNervusAntenna( ));
		for( int j=0; j<OUTPUT_SIGNAL_COUNT*4-1; j++ )
		{
			pNervus->AddInputAntenna( new CNervusAntenna( ) );
		}

		if( i!=0 )
			m_pNervusNet[nIdx]->AddNervusAtLine( 4, pNervus );
	}

	NervusLink *nl = new NervusLink[3000];
	int nLinkCount=0;
	//0 to 1
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		NervusLink tmpnl={ {0,i}, 0, {1,i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		NervusLink tmpnl={ {0,i}, 1, {1,INPUT_SIGNAL_COUNT+i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT; i++ )
	{
		if( i==0 )
		{
			NervusLink tmpnl={ {0,i}, 2, {1,INPUT_SIGNAL_COUNT*2-1} };
			nl[nLinkCount++] = tmpnl;
		}
		else
		{
			NervusLink tmpnl={ {0,i}, 2, {1,INPUT_SIGNAL_COUNT+i-1} };
			nl[nLinkCount++] = tmpnl;
		}
	}
	//1 to 2
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		NervusLink tmpnl={ {1,i}, 0, {2,i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		NervusLink tmpnl={ {1,i}, 1, {2,INPUT_SIGNAL_COUNT*2+i} };
		nl[nLinkCount++] = tmpnl;
	}
	for( int i=0; i<INPUT_SIGNAL_COUNT*2; i++ )
	{
		if( i==0 )
		{
			NervusLink tmpnl={ {1,i}, 2, {2,INPUT_SIGNAL_COUNT*2*2-1} };
			nl[nLinkCount++] = tmpnl;
		}
		else
		{
			NervusLink tmpnl={ {1,i}, 2, {2,INPUT_SIGNAL_COUNT*2+i-1} };
			nl[nLinkCount++] = tmpnl;
		}
	}
	//2 to 3
	for( int i=0; i<INPUT_SIGNAL_COUNT*2*2; i++ )
		for( int j=0; j<OUTPUT_SIGNAL_COUNT*4; j++ )
		{
			NervusLink tmpnl={ {2,i}, j, {3,j} };
			nl[nLinkCount++] = tmpnl;
		}
	//3 to 4
	for( int i=0; i<OUTPUT_SIGNAL_COUNT*4; i++ )
		for( int j=0; j<OUTPUT_SIGNAL_COUNT; j++ )
		{
			NervusLink tmpnl={ {3,i}, j, {4,j} };
			nl[nLinkCount++] = tmpnl;
		}

	for( int i=0; i<nLinkCount; i++ )
		m_pNervusNet[nIdx]->MakeConnection( nl[i].posSource, nl[i].nSourcePinIdx, nl[i].posTarget );

	for( int i=0; i<nRateCount; i++ )
	{
		m_pNervusNet[nIdx]->SetOutputAntennaRate( tryRate1[i].posSource,  tryRate1[i].nSourcePinIdx,  tryRate1[i].fRate );
		m_pNervusNet[nIdx]->SetOutputAntennaRate( tryRate2[i].posSource,  tryRate2[i].nSourcePinIdx+OUTPUT_SIGNAL_COUNT-1,  tryRate2[i].fRate );
		m_pNervusNet[nIdx]->SetOutputAntennaRate( tryRate3[i].posSource,  tryRate3[i].nSourcePinIdx+OUTPUT_SIGNAL_COUNT*2-1,  tryRate3[i].fRate );
		m_pNervusNet[nIdx]->SetOutputAntennaRate( tryRate4[i].posSource,  tryRate4[i].nSourcePinIdx+OUTPUT_SIGNAL_COUNT*3-1,  tryRate4[i].fRate );
	}

	delete nl;
}

float CeBrain::RunAllTrainingCase2( OutputAntennaRate* pRate1, OutputAntennaRate* pRate2, OutputAntennaRate* pRate3, OutputAntennaRate* pRate4, int nRateCount, OutputAntennaRate* pTryRate, int nTryRateCount )
{
	int nOkCount = 0;

	#pragma omp parallel for
	for( int i=0; i<MAX_CASE; i++ )
	{
		BuildNervusNet2(i, pRate1, pRate2, pRate3, pRate4, nRateCount);
		SetNervusRates( i, pTryRate, nTryRateCount );

		if( RunTrainingCase( i ) )
			nOkCount++;
		ClearNervusNet(i);
	}
	float fPassRate = ((float)nOkCount)/MAX_CASE*100;
	TRACE( "Case Pass %d, when try %lf, pass rate: %f%%\n", nOkCount, pTryRate[0].fRate, fPassRate );

	return fPassRate;
}

void CeBrain::DisplayNervusMap( void )
{
	CTrainingCase* pCase = m_pTrainingCaseDB->GetCase( 0 );

	pCase->ConnectInputOutput( m_pNervusNet[0] );
	m_pNervusNet[0]->DisplayNervusMap();
}

void CeBrain::SetNervusRates( int nIdx, OutputAntennaRate* pRate, int nRateCount )
{
	for( int i=0; i<nRateCount; i++ )
		m_pNervusNet[nIdx]->SetOutputAntennaRate( pRate[i].posSource,  pRate[i].nSourcePinIdx,  pRate[i].fRate );
}
